﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace pkufi_tools
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            AdjustControls();
            InitKeys();

            tbAesKey.TextChanged += TbAesKey_TextChanged;
            tbMd5Key.TextChanged += TbMd5Key_TextChanged;
            btnDecrypt.Click += BtnDecrypt_Click;
        }

        private void BtnDecrypt_Click(object sender, EventArgs e)
        {
            Decrypt();
        }

        private void TbMd5Key_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(tbMd5Key.Text))
            {
                MessageBox.Show("MD5 Key不能为空。", "密钥为空", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            md5Key = tbMd5Key.Text.Trim();
        }

        private void TbAesKey_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(tbAesKey.Text))
            {
                MessageBox.Show("AES密钥不能为空。", "密钥为空", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            string key = tbAesKey.Text.Trim();
            //if (key.Length != 16)
            //{
            //    MessageBox.Show("AES密钥长度必须是16位。", "密钥长度错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            //    return;
            //}
            aesKey = key;
        }

        private void tpEncrypt_SizeChanged(object sender, EventArgs e)
        {
            AdjustControls();
        }

        private void btnEncrpt_Click(object sender, EventArgs e)
        {
            Encrypt();
        }

        /// <summary>
        /// 调整控件的尺寸和位置
        /// </summary>
        private void AdjustControls()
        {
            int height = tpEncrypt.Size.Height;
            tbDecrypted.Height = height / 2 - 15 - tbDecrypted.Top;

            tbEncrypted.Height = height / 2 - 30;
            tbEncrypted.Top = height / 2 + 15;
            lblEncrypted.Top = tbEncrypted.Top;
            btnDecrypt.Top = tbEncrypted.Top;
        }

        private void InitKeys()
        {
            tbAesKey.Text = aesKey;
            tbMd5Key.Text = md5Key;
        }

        private void Encrypt()
        {
            //明文，已经是字符串了，不用做序列化了
            string jsonContent = tbDecrypted.Text.Trim();
            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                MessageBox.Show("报文为空", "报文为空", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //data部分
            //AES加密
            string b = Base64Encode(jsonContent);
            //MD5加密
            byte[] c = AesEncrypt(b);
            //再AES加密
            string data = Base64Encode(c);

            //sign部分
            string sign = GetMD5(b + md5Key);

            tbEncrypted.Text = string.Format("{{ \"data\": \"{0}\", \"sign\": \"{1}\" }}", data, sign);
        }

        private void Decrypt()
        {
            //是字符串，要解析为JSON对象，取出data和sign
            string json = tbEncrypted.Text.Trim();
            if (string.IsNullOrWhiteSpace(json))
            {
                MessageBox.Show("报文为空", "报文为空", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            JsonObj jsonObj = JsonConvert.DeserializeObject<JsonObj>(json);

            string data = jsonObj.data;
            byte[] c = Base64Decode(data);
            string b = AesDecypt(c);
            string a = encoding.GetString(Base64Decode(b));

            //格式化
            dynamic obj = JsonConvert.DeserializeObject(a);

            tbDecrypted.Text = JsonConvert.SerializeObject(obj, Formatting.Indented);
        }

        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="content">待加密的明文</param>
        /// <returns></returns>
        private string Base64Encode(object content)
        {
            string encode = string.Empty;
            byte[] bytes = null;
            if (content.GetType() == typeof(string)) bytes = encoding.GetBytes((string)content);
            else bytes = (byte[])content;

            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch (Exception e)
            {
                encode = "Base64加密异常:" + e.Message + (string)content;
            }
            return encode;
        }

        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="content">待解密的密文</param>
        /// <returns></returns>
        private byte[] Base64Decode(string content)
        {
            return Convert.FromBase64String(content);
        }

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="encrypt">要加密的内容</param>
        /// <returns></returns>
        private byte[] AesEncrypt(string encrypt)
        {
            using (RijndaelManaged cipher = new RijndaelManaged())
            {
                cipher.Mode = CipherMode.ECB;
                cipher.Padding = PaddingMode.PKCS7;
                cipher.KeySize = 128;
                cipher.BlockSize = 128;
                cipher.Key = GetAesSha1PrngKey(aesKey);

                byte[] valueBytes = encoding.GetBytes(encrypt);

                byte[] encrypted;
                using (ICryptoTransform encryptor = cipher.CreateEncryptor())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream writer = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                        {
                            writer.Write(valueBytes, 0, valueBytes.Length);
                            writer.FlushFinalBlock();
                            encrypted = ms.ToArray();
                            return encrypted;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="encrypted">要解密的密文</param>
        /// <returns></returns>
        private string AesDecypt(byte[] encrypted)
        {
            using (RijndaelManaged cipher = new RijndaelManaged())
            {
                cipher.Mode = CipherMode.ECB;
                cipher.Padding = PaddingMode.PKCS7;
                cipher.KeySize = 128;
                cipher.BlockSize = 128;
                cipher.Key = GetAesSha1PrngKey(aesKey);
                //cipher.IV = GetAesSha1PrngKey(secretKey);

                using (ICryptoTransform decryptor = cipher.CreateDecryptor())
                {
                    using (MemoryStream msDecrypt = new MemoryStream(encrypted.ToArray()))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
                                return srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 对明文密钥进行二次处理,在此方法返回得到的才是真正的密钥Key
        /// </summary>
        /// <param name="seed"></param>
        /// <returns></returns>
        private byte[] GetAesSha1PrngKey(string seed)
        {
            using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
            {
                byte[] result = new byte[16];
                Array.Copy(sha1.ComputeHash(sha1.ComputeHash(encoding.GetBytes(seed))), result, result.Length);
                return result;
            }
        }

        /// <summary>
        /// 获取MD5值
        /// </summary>
        /// <param name="source">加密的字符串</param>
        /// <returns>返回MD5值</returns>
        private string GetMD5(string source)
        {
            byte[] sor = Encoding.UTF8.GetBytes(source);
            MD5 md5 = MD5.Create();
            byte[] result = md5.ComputeHash(sor);
            StringBuilder strbul = new StringBuilder(40);
            for (int i = 0; i < result.Length; i++)
            {
                strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位
            }
            return strbul.ToString();
        }



        private string aesKey = "0123456789ABCDEF";
        private string md5Key = "12345";
        private Encoding encoding = Encoding.UTF8;
    }

    public class JsonObj
    {
        public string data;
        public string sign;
    }
}
